package com.ahdms.es.ocsp;

import com.ahdms.es.gm.constant.IKIObjectIdentifiers;
import com.ahdms.es.util.AsnUtil;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.ocsp.*;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;

import java.io.IOException;
import java.io.OutputStream;
import java.text.ParseException;
import java.util.*;

/**
 * ocsp响应(OCSPResponse)解析工具类
 * @Title 
 * @Description 
 * @Copyright <p>Copyright (c) 2015</p>
 * @Company <p>迪曼森标识技术有限公司Co., Ltd.</p>
 * @author hexin
 * @version 1.0
 * @修改记录
 * @修改序号，修改日期，修改人，修改内容
 */
public class OCSPResponseHandle {
    private OCSPRequest ocspRequest;  	  //ocsp请求
    private OCSPResponse ocspResponse;    //ocsp响应

    /**
     * 构造OCSPResponseHandle函数
     * @创建人 hexin
     * @创建时间 2017年8月8日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @param ocspRequest ocsp请求
     * @param ocspResponse ocsp响应
     */
    public OCSPResponseHandle(OCSPRequest ocspRequest, OCSPResponse ocspResponse) {
        if(null == ocspRequest){
        	throw new NullPointerException("OCSPResponseHandle ocspRequest null");
        }else if(null == ocspResponse){
        	throw new NullPointerException("OCSPResponseHandle ocspResponse null");
        }else{
        	this.ocspRequest = ocspRequest;
        	this.ocspResponse = ocspResponse;
        }
    }

    /**
     * 获取ocsp响应码
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @return
     */
    public int getOCSPResponseCode(){
    	return ocspResponse.getResponseStatus().getValue().intValue();
    }
    
    
    /**
     * 获取ocsp签名原文
     * @创建人 liuyipin
     * @创建时间 2018年4月25日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @return
     * @throws IOException 
     */
    public byte[] getOCSPResponeSignSource() throws IOException{
    	byte[] responseData = null;
    	if(getOCSPResponseCode() == 0){
    		BasicOCSPResponse basicOCSPResponse = getBasicOCSPResponse(ocspResponse);
    		responseData = basicOCSPResponse.getTbsResponseData().getEncoded(); 
    	}
		return responseData;
    	
    }
    
    
    /**
     * 获取ocsp响应签名证书
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @return
     */
    public Certificate getOCSPSignCert(){
    	Certificate ocspSignCert = null;
    	
    	if(getOCSPResponseCode() == 0){
    		BasicOCSPResponse basicOCSPResponse = getBasicOCSPResponse(ocspResponse);
    		ASN1Sequence certs = basicOCSPResponse.getCerts();
    		Enumeration e = certs.getObjects();
    		if(null!=e && e.hasMoreElements()){
    			ocspSignCert = Certificate.getInstance(e.nextElement());//ocsp签名证书
    		}
    	}

		return ocspSignCert;
    }
    
    /**
     * 获取ocsp签名算法标识
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @return
     */
    public AlgorithmIdentifier getAlgorithmIdentifier(){
    	AlgorithmIdentifier signatureAlgorithm = null;
    	
    	if(getOCSPResponseCode() == 0){
    		BasicOCSPResponse basicOCSPResponse = getBasicOCSPResponse(ocspResponse);
			signatureAlgorithm = basicOCSPResponse.getSignatureAlgorithm();//ocsp签名算法
    	}

    	return signatureAlgorithm;
    }

    /**
     * 获取ocsp签名值
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @return
     */
    public byte[] getOCSPSignature(){
    	byte[] signature = null; 
    	
    	if(getOCSPResponseCode() == 0){
    		BasicOCSPResponse basicOCSPResponse = getBasicOCSPResponse(ocspResponse);
    		signature = basicOCSPResponse.getSignature().getOctets();//ocsp签名值
    	}
    	
    	return signature;
    }
    
    /**
     * 解析OCSPResponse获取证书状态数据
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @param verifier
     * @return
     */
    public OCSPRespondVO getCertStatusInfos(OCSPContentVerifier verifier) {
    	OCSPRespondVO respondVO = new OCSPRespondVO();
    	
        if(getOCSPResponseCode() != 0){
        	respondVO.setRespValue(getOCSPResponseCode());
        }else{
        	//校验ocspResponse响应
        	int checkCode = checkResPars(verifier);
        	if(checkCode== 0){//校验OCSPResponse成功
				//获取响应证书信息集合
				List<SingleCertVO> certInfos = getRespondCertInfos();
				respondVO.setCertInfos(certInfos);
        	}
        	respondVO.setRespValue(checkCode);
        }

        return respondVO;
    }

    /**
     * 获取OCSPResponse请求中的BasicOCSPResponse结构数据
     * @创建人 hexin
     * @创建时间 2017年8月9日
     * @创建目的【】
     * @修改目的【修改人：，修改时间：】
     * @param ocspResponse OCSPResponse请求
     * @return
     */
    private BasicOCSPResponse getBasicOCSPResponse(OCSPResponse ocspResponse){
		ResponseBytes responseBytes = ocspResponse.getResponseBytes();
		ASN1Sequence asn1Sequence = AsnUtil.byteToASN1Sequence(responseBytes.getResponse().getOctets());
		BasicOCSPResponse basicOCSPResponse = BasicOCSPResponse.getInstance(asn1Sequence);
		return basicOCSPResponse;
    }

	/**
	 * 校验OCSPResponse响应数据
	 * @创建人 hexin
	 * @创建时间 2017年8月9日
	 * @创建目的【】
	 * @修改目的【修改人：，修改时间：】
	 * @param verifier 数据验证结构
	 * @return
	 */
	private int checkResPars(OCSPContentVerifier verifier){
		Date nowTime = new Date();//系统当前时间
		int result = 0; //默认校验成功
		int ocspResponseCode = ocspResponse.getResponseStatus().getValue().intValue();//响应返回码
		if(ocspResponseCode== 0){//响应成功

			ResponseBytes responseBytes = ocspResponse.getResponseBytes();
			ASN1Sequence asn1Sequence = AsnUtil.byteToASN1Sequence(responseBytes.getResponse().getOctets());
			BasicOCSPResponse basicOCSPResponse = BasicOCSPResponse.getInstance(asn1Sequence);
			ResponseData tbsResponseData = basicOCSPResponse.getTbsResponseData();
			ASN1GeneralizedTime producedAt = tbsResponseData.getProducedAt();//ocsp响应时间
			
			Date resTime = null;//ocsp响应时间
			try {
				resTime =  producedAt.getDate();
			} catch (ParseException e1) {
				e1.printStackTrace();
			}
			
			//校验ocsp响应时间
			//if(null!=resTime && nowTime.compareTo(resTime)==1){
			if(true){
				
				//校验ocsp响应类型
				ASN1ObjectIdentifier responseType = responseBytes.getResponseType();//ocsp响应类型
				if(responseType.equals(OCSPObjectIdentifiers.id_pkix_ocsp_basic)){
					
					//校验ocsp签名算法
					AlgorithmIdentifier signatureAlgorithm = basicOCSPResponse.getSignatureAlgorithm();//ocsp签名算法
					if(signatureAlgorithm.getAlgorithm().equals(IKIObjectIdentifiers.sm2_with_sm3)){
						
						Extension reqNonce = null;//请求中的随机数扩展项
						Extensions  requestExtensions = ocspRequest.getTbsRequest().getRequestExtensions();
						if(null!=requestExtensions){
							reqNonce = requestExtensions.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
						}
						
						Extension resNonce = null;//响应中的随机数扩展项
						Extensions responseExtensions = tbsResponseData.getResponseExtensions();
						if(null!=responseExtensions){
							resNonce = responseExtensions.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
						}
						
						//校验请求响应随机数扩展项
						if(null==resNonce || resNonce.equals(reqNonce)){

							//校验ocsp签名值
							/*
							try {
								if(!verifySign(verifier, tbsResponseData)){
									result = Constants.OCSP_SIGN_VERIFY_ERROR;
								}
							} catch (IOException e) {
								result = Constants.OCSP_SIGN_VERIFY_ERROR;
								e.printStackTrace();
							}
							*/

						}else{
							result = Constants.OCSP_NONCE_ERROR;
						}
						
					}else{
						result = Constants.OCSP_SIGN_ALGORITHM_ERROR;
					}

				}else{
					result = Constants.OCSP_RES_TYPE_ERROR;
				}
				
			}else{
				result = Constants.OCSP_RES_TIME_ERROR;
			}

		}else{
			result = ocspResponseCode;
		}
		return result;
	}
	
	/**
	 * 获取响应证书信息
	 * @创建人 hexin
	 * @创建时间 2017年2月17日
	 * @创建目的【】
	 * @修改目的【修改人：，修改时间：】
	 * @return
	 */
	private List<SingleCertVO> getRespondCertInfos(){
		Date nowTime = new Date();//系统当前时间
		
		ASN1Sequence requestList = ocspRequest.getTbsRequest().getRequestList();//ocsp请求列表
		
		BasicOCSPResponse basicOCSPResponse = getBasicOCSPResponse(ocspResponse);
		ResponseData tbsResponseData = basicOCSPResponse.getTbsResponseData();
		ASN1Sequence responseList = tbsResponseData.getResponses();//ocsp响应列表
		
		List<SingleCertVO> certInfos = new ArrayList<SingleCertVO>();
		Enumeration e1 = requestList.getObjects();
		Enumeration e2 = responseList.getObjects();
		
		while(e2.hasMoreElements()){
			
			SingleCertVO singleCertVO = new SingleCertVO(); //证书信息
			SingleResponse singleResponse = SingleResponse.getInstance(e2.nextElement()); //单个响应
			Request request = Request.getInstance(e1.nextElement()); //单个请求

			Date thisUpdate = null; //ocsp证书状态更新时间
			try {
				thisUpdate =  singleResponse.getThisUpdate().getDate();
			} catch (ParseException e) {
				e.printStackTrace();
			}
			
			//判断证书状态本次更新时间是否合法
			//if(null!=thisUpdate && nowTime.compareTo(thisUpdate)==1){
			if(true){
				
				//比对单个请求，单个响应结构中证书标识CertID结构数据是否完全匹配
				if(compareCertID(request.getReqCert(), singleResponse.getCertID())){
					
					singleCertVO.setRespValue(Constants.SUCCESSFUL);
					singleCertVO.setUpdateTime(thisUpdate);
					singleCertVO.setSerialNumber(singleResponse.getCertID().getSerialNumber().getPositiveValue().intValue());
					singleCertVO.setStatus(String.valueOf(singleResponse.getCertStatus().getTagNo()));
					if((singleResponse.getCertStatus().getTagNo()) == 1){//证书为撤销状态
						RevokedInfo revokedInfo = (RevokedInfo)singleResponse.getCertStatus().getStatus();
						singleCertVO.setRevokReason(String.valueOf(revokedInfo.getRevocationReason().getValue().intValue()));
					}

				}else{
					singleCertVO.setSerialNumber(singleResponse.getCertID().getSerialNumber().getPositiveValue().intValue());
					singleCertVO.setRespValue(Constants.OCSP_CERTID_ERROR);
				}
				
			}else{
				singleCertVO.setRespValue(Constants.OCSP_THISUPDATETIME_ERROR);
			}
			
			certInfos.add(singleCertVO);
			
		}

		return certInfos;
	}
	
	/**
	 * 比对两个CertID
	 * @创建人 hexin
	 * @创建时间 2017年2月17日
	 * @创建目的【】
	 * @修改目的【修改人：，修改时间：】
	 * @param c1
	 * @param c2
	 * @return
	 */
	private boolean compareCertID(CertID c1, CertID c2){
//		boolean result = false;//默认两个CertID不匹配

		return Objects.equals(c1.getHashAlgorithm().getAlgorithm(),c2.getHashAlgorithm().getAlgorithm())
				&& Objects.equals(c1.getIssuerNameHash(),c2.getIssuerNameHash())
				&& Objects.equals(c1.getIssuerKeyHash(),c2.getIssuerKeyHash())
				&& Objects.equals(c1.getSerialNumber(),c2.getSerialNumber());
//		if((c1.getHashAlgorithm().getAlgorithm()).equals((c2.getHashAlgorithm().getAlgorithm()))){
//			if((c1.getIssuerNameHash()).equals((c2.getIssuerNameHash()))){
//				if((c1.getIssuerKeyHash()).equals((c2.getIssuerKeyHash()))){
//					if((c1.getSerialNumber()).equals((c2.getSerialNumber()))){
//						result = true;
//					}
//				}
//			}
//		}
	}
	
	/**
	 * 验证OCSPRespons响应中ResponseData数据结构的签名
	 * @创建人 hexin
	 * @创建时间 2017年8月9日
	 * @创建目的【】
	 * @修改目的【修改人：，修改时间：】
	 * @param verifier
	 * @param tbsObj
	 * @return
	 * @throws IOException
	 */
    private boolean verifySign(OCSPContentVerifier verifier, ASN1Encodable tbsObj)
            throws IOException
        {
            OutputStream sOut = verifier.getOutputStream();
            DEROutputStream dOut = new DEROutputStream(sOut);
            dOut.writeObject(tbsObj);
            sOut.close();
            return verifier.verify();
        }
}
